package main

import (
	//"os"
	"bufio"
	"fmt"
	"os"
	"strings"
	"sync"
	"time"

	"github.com/panjf2000/gnet/v2"
	log "github.com/sirupsen/logrus"

	"cybertwin/ue"
	"cybertwin/utils/protocol"
	"cybertwin/utils/stringutils"
	"cybertwin/utils/timer"
)

var mu sync.RWMutex
var access_timer map[string]*timer.Timer

func register() (err error) {
	return
}

func runAPClient(apClient *ue.ApClient) (err error) {
	//dir, err := os.Getwd()
	ueid := apClient.Ueid
	mu.Lock()
	access_timer[ueid] = &timer.Timer{}
	access_timer[ueid].Begin()
	mu.Unlock()

	wg := &sync.WaitGroup{}
	apClient.Wg = wg
	wg.Add(1)

	cli, err := gnet.NewClient(apClient)
	if err != nil {
		log.Errorln("runAPClient:", err.Error())
		return
	}
	err = cli.Start()
	_, err = cli.Dial("tcp", "127.0.0.1:8082")
	if err != nil {
		log.Errorln("runAPClient:", err.Error())
		return
	}

	wg.Wait()
	cli.Stop()

	return
}

func runCyberTwinClient(ctClient *ue.CybertwinClient) (conn gnet.Conn, err error) {

	wg := &sync.WaitGroup{}
	ctClient.Wg = wg
	wg.Add(1)

	cli, err := gnet.NewClient(ctClient)
	if err != nil {
		log.Errorln("runCyberTwinClient:", err.Error())
		return
	}
	err = cli.Start()
	// IP地址和端口号不应该是写死的，应该是AP告知的
	conn, err = cli.Dial("tcp", fmt.Sprintf("%s:%s", ctClient.Ip, ctClient.Port))
	if err != nil {
		log.Errorln("runCyberTwinClient:", err.Error())
		return
	}

	wg.Wait()

	//mu.RLock()
	dura := access_timer[ctClient.Ueid].Stop()
	//mu.RUnlock()

	log.Infof("Access Time Cost:%v", dura)

	return
}

func makeRequest(ctClient *ue.CybertwinClient, conn gnet.Conn, requestid uint32) (err error) {
	ctClient.Req_map[requestid] = &timer.Timer{}
	ctClient.Req_map[requestid].Begin()
	echo_message := []byte("Hello, Cybertwin!")
	reqHeader := protocol.Request_Header{
		ProviderID:  uint32(1 << 30),
		ServiceID:   uint32(1 << 15),
		RequestID:   requestid,
		Token:       0, //ctClient.Token,
		DataSize:    uint32(len(echo_message)),
		Dscp:        7,
		State:       0,
		MaxRespTime: 5,
	}
	body, _ := protocol.CodecUtils.RequestProtocolCodec.AppendHeader(reqHeader, echo_message)
	data, _ := protocol.CodecUtils.AccessProtocolCodec.AESEncode(body, protocol.TYPE_UE_CYBERTWIN_REQUEST, ctClient.Ck3)
	_, err = conn.Write(data)
	if err != nil {
		return
	}
	log.Infof("[UE] UE %s has sent a request, requestid = %d\n", stringutils.GetPrefix(ctClient.Ueid, 9), requestid)
	return
}

func new_ue(ueid string, hid string) {
	apClient := ue.ApClient{
		Ueid: ueid,
		Hid:  hid,
	}
	err := runAPClient(&apClient)
	if err != nil {
		log.Errorln("run AP client failed")
		return
	}

	ctClient := ue.CybertwinClient{
		Ueid:       apClient.Ueid,
		R3:         apClient.R3,
		Token:      apClient.Token,
		CanRequest: false,
		Ip:         apClient.Ct_ip,
		Port:       apClient.Ct_port,
	}
	conn, err := runCyberTwinClient(&ctClient)
	if err != nil {
		log.Errorln("run Cybertwin Client failed")
		return
	}
	//log.Infof("UE Client is ready to make request\n")
	for i := 1; i < 6; i++ {
		if ctClient.CanRequest {
			// 发请求
			err := makeRequest(&ctClient, conn, uint32(i))
			if err != nil {
				log.Errorln("make request failed:", err.Error())
			}
		}
		time.Sleep(time.Second * 1)
	}
}

func main() {
	fileName := "ue_info.txt"

	file, err := os.Open(fileName)
	if err != nil {
		log.Errorln(err.Error())
		return
	}
	defer file.Close()
	scanner := bufio.NewScanner(file)

	access_timer = make(map[string]*timer.Timer)

	var cnt = 1
	for scanner.Scan() {
		cnt++
		if cnt > 10 {
			break
		}
		line := scanner.Text()
		slices := strings.Split(line, " ")
		ueid := slices[0]
		hid := slices[1]
		go new_ue(ueid, hid)
	}
	time.Sleep(time.Second * 50)
}
